# -*- encoding: utf-8 -*-
"""
    File : main.py
"""

import time, re, os, json
from fastapi import FastAPI, Path, Form, Query, Depends, Header, HTTPException, Request, File, UploadFile
from fastapi.middleware.gzip import GZipMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
# from fastapi.encoders import jsonable_encoder
from fastapi.responses import JSONResponse

import pymongo

import openpyxl
from openpyxl import Workbook, load_workbook

from myenum import DepartmentName, GradeName, MajorName, SubjectName
import math
import requests

app = FastAPI()
app.add_middleware(GZipMiddleware, minimum_size=500)
app.mount("/output", StaticFiles(directory="output"), name="output")
templates = Jinja2Templates(directory="templates")
MongoDB_Host = '106.75.215.81'
MongoDB_Port = 27027
MongoDB_User = 'root'
MongoDB_Pwd = 'guojia'
AppID = 'wx53b79f1eab04c30b'
AppSecret = '1a5cc382f065b8b553d16677fb619f29'
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
APP_UPLOAD = os.path.join(APP_ROOT, 'upload')
APP_OUTPUT = os.path.join(APP_ROOT, 'output')

client = pymongo.MongoClient(host=MongoDB_Host, port=MongoDB_Port, username=MongoDB_User,password=MongoDB_Pwd)

async def is_number(s):
    try:
        float(s)
        return True
    except ValueError:
        pass
 
    try:
        import unicodedata
        unicodedata.numeric(s)
        return True
    except (TypeError, ValueError):
        pass
 
    return False

async def get_token_header(x_token: str = Header(...)):
    if x_token != "guojia":
        raise HTTPException(status_code=400, detail="X-Token header invalid")

@app.middleware("http")
async def add_process_time_header(request: Request, call_next):
    start_time = time.time()
    response = await call_next(request)
    process_time = time.time() - start_time
    response.headers["X-Process-Time"] = str(process_time)
    return response

@app.post("/upload", tags=["Search Scores Interfaces 信息工程系查成绩接口"], dependencies=[Depends(get_token_header)] )
async def file_upload(file: UploadFile = File(...)):
    start = time.time()
    try:
        extension = os.path.splitext(file.filename)[-1]
        temp_file = os.path.join('upload', 'tmp' + extension)
        # print('extension %r.'%(extension) )
        # print('temp_file %r.'%(temp_file) )
        content = await file.read()
        with open(temp_file, 'wb') as f:
            f.write(content)
        return {"message": "success", 'time': time.time() - start, 'filename': file.filename}
    except Exception as e:
        return {"message": str(e), 'time': time.time() - start, 'filename': file.filename}

@app.get("/parser", tags=["Search Scores Interfaces 信息工程系查成绩接口"], dependencies=[Depends(get_token_header)] )
async def parser(   department: DepartmentName = Query(..., description="请选择院系"),
                    grade: GradeName = Query(..., description="请选择年级"),
                    major: MajorName = Query(..., description="请选择专业"),
                    subject: SubjectName = Query(..., description="请选择学科")):
    # print("You Choice %r" %(major))
    
    xlsx = os.path.join(APP_UPLOAD, 'tmp.xlsx')
    # print('xlsx: %r' %(xlsx))

    wb = load_workbook(xlsx, data_only=True)
    # print(wb.sheetnames)
    sheet = wb.active
    # print(sheet.title)
    rows = sheet.max_row
    columns = sheet.max_column
    # print('rows %r columns %r' %(rows, columns))
    
    db = client.xinxi
    mStudent = db.student
    
    rowList = []
    for row in sheet.rows:
        for col in row:
            # print(' row %r col %r' %(row , col))
            match = re.match(r'^\d{9,}$', str(col.value))
            
            if match:
                # print('match %r ok. %r'%(match, str(col.value)) )
                tmpList = []
                for col in row:
                    # print( 'col : %r.' %( str(col.value) ) )
                    tmpList.append(str(col.value))
                
                rowList.append( tmpList )

                InsertNo = tmpList[0]
                InsertName = tmpList[1]
                InsertGrade = grade
                InsertDepartment = department
                InsertMajor = major
                Example = { "no": InsertNo,
                            "name": InsertName,
                            "grade": InsertGrade,
                            "department": InsertDepartment,
                            "major": InsertMajor,
                            "scores": [] }
                
                if mStudent.find({"no": InsertNo}).count() == 0:
                    print("Not Found")
                    mStudent.insert(Example)
                else:
                    print("Found")
                    mStudent.update({"no": InsertNo},{"$set":{"major": InsertMajor}})
                
                # str( round( float(i['score']) ) )

                score = "0"
                # print("tmpList[5].isdigit() %r %r %r" %(tmpList[5].isdigit(), type(str(tmpList[5]).isdigit()), tmpList[5] ) )
                if is_number( tmpList[5] ):
                    score = str( round( float(tmpList[5]) ) )
                
                # print('score %r tmpList[5] %r' %(score, tmpList[5]))

                guojia = {  "no": InsertNo,
                            "name": InsertName,
                            "grade": InsertGrade,
                            "department": InsertDepartment,
                            "major": InsertMajor,
                            "scores": [{"course": subject, "score": score}] }
    
                mResult = mStudent.find({   "no": guojia["no"], 
                                            # "name": guojia["name"],
                                            # "major": guojia["major"],
                                            "scores": {"$elemMatch":{"course": guojia["scores"][0]["course"]}}})
                print('Found 学科 Count %r.' %(mResult.count()) )
                if mResult.count() == 0:
                    mStudent.update({   "no": guojia['no']
                                    },
                                    {'$addToSet' : {"scores": {"course": guojia["scores"][0]["course"], "score": guojia["scores"][0]["score"]} } } )
                else:
                    mStudent.update({   "no": guojia['no'],
                                        # "name": guojia['name'],
                                        # "major": guojia['major'],
                                        "scores.course": {'$eq' : guojia['scores'][0]['course']}
                                    },
                                    {'$set': {'scores.$.score': guojia['scores'][0]['score'],
                                                "department": guojia['department'],
                                                "grade": guojia['grade'],
                                                "major": guojia['major']},
                                      } )
                                      #"grade": InsertGrade,"department": InsertDepartment,
            else:
                break
    rowListLen = len(rowList)
    # print('rowList %r Len %r' %( rowList, rowListLen ) )
    
    dic = {}
    if rowListLen == 0:
        dic = {"code": 404, "major": major, "datas": {"no": 0}}
    else:
        dic = {"code": 200, "status": "Ok"}
    return dic

@app.get("/search/{no}", tags=["Search Scores Interfaces 信息工程系查成绩接口"], dependencies=[Depends(get_token_header)] )
async def search( no: int=Path(..., ge=0) ):
    
    db = client.xinxi
    mStudent = db.student
    # print("Enter no : %r" %(no))
    mResult = mStudent.find_one( {"no": str(no) }, {"_id" : 0} )
    dic = {"code": 404, "datas": {}}
    if mResult:
        # print('find_one %r' %(mResult))
        dic["code"] = 200
        dic["datas"].update(mResult)
    
    return dic

@app.post("/add", tags=["Porject Add Interfaces 信息工程系查成绩接口"], dependencies=[Depends(get_token_header)] )
async def add(  name: str=Query(...),
                img: str=Query(...) ):
    # print('name %r' %(name))
    # print('img %r' %(img))
     
    db = client.xinxi
    mProject = db.project

    mSingleProject = {'name': name, 'img': img}
    mResult = mProject.find({'name': name})
    if mResult.count() == 0:
        mProject.insert(mSingleProject)
    else:
        mProject.update({'name': name}, {'$set':{'img': img}})

    mResult = mProject.find({},{'_id': 0})
    mTmpList = []
    dic = {"code": 404, "datas": []}
    for item in mResult:
        mTmpList.append(item)
    # print('mTmpList %r' %(mTmpList))
    if mResult:
        dic["code"]=200
        dic["datas"]=mTmpList
    return dic

@app.get("/projects", tags=["Porject Add Interfaces 信息工程系查成绩接口"], dependencies=[Depends(get_token_header)] )
async def projects():
     
    db = client.xinxi
    mProject = db.project

    mResult = mProject.find({},{'_id': 0})
    mTmpList = []
    dic = {"code": 404, "length": 0, "datas": []}
    for item in mResult:
        mTmpList.append(item)
    # print('mTmpList %r' %(mTmpList))
    if mResult:
        dic["code"]=200
        dic["length"]=len(mTmpList)
        dic["datas"]=mTmpList
    return dic


@app.get("/CodeForId/{code}", tags=["Porject Add Interfaces 信息工程系查成绩接口"], dependencies=[Depends(get_token_header)] )
async def CodeForId( code: str=Query(...)):
    appid = 'wx53b79f1eab04c30b'
    secret = '1a5cc382f065b8b553d16677fb619f29'
    url = 'https://api.weixin.qq.com/sns/jscode2session?appid=' + appid + '&secret=' + secret + '&js_code=' + code + '&grant_type=authorization_code';
    
    print('url: ' + url)
    responses = requests.get(url)
    # 查看响应内容，responses.text 返回的是Unicode格式的数据
    print('text:' + responses.text)
    print('code:' + code)
    # 查看响应内容，responses.content返回的字节流数据
    print('content:' + str(responses.content) )
    # 查看完整url地址
    print('url:' + responses.url)
    # 查看响应头部字符编码
    print('encoding:' + responses.encoding)
    # 查看响应码
    print('status code:' + str(responses.status_code) )

    return JSONResponse( content = json.loads(responses.text) )

@app.get("/", tags=["Test Interfaces"])
def home(request: Request):
    return templates.TemplateResponse("index.html", {"request": request})

@app.get("/title/{title}", tags=["Test Interfaces"])
def title(request: Request, title: str = Query(None)):
    return templates.TemplateResponse("index.html", {"request": request, 
                                        "title": title})

@app.get("/rounds", tags=["Test Interfaces"])
def rounds(request: Request):
     
    db = client.xinxi
    mStudent = db.student
    print("All Total :%r" %(mStudent.count_documents({})))
    mResult = mStudent.find({},{'_id': 0})
    # mResult = mStudent.find({"name":"王浩"},{'_id': 0})
    print("王浩All Total :%r" %(mStudent.count_documents({"name":"王浩"})))
    mTmpList = []
    dic = {"code": 404, "datas": []}
    for item in mResult:
        mTmpList.append(item)
        # print('item %r' %(item))
        print('item %r' %(item["scores"]))
    # print('mTmpList %r' %(mTmpList))
    if mResult:
        dic["code"]=200
        dic["datas"]=mTmpList
    return dic

@app.get("/printEnum", tags=["Test Interfaces"])
def printEnum(request: Request):
    for item in GradeName:
        print('Grade(年级) %r' %(item))
    for item in DepartmentName:
        print('Department(院系) %r' %(item))
    for item in MajorName:
        print('Major(专业) %r' %(item))
    for item in SubjectName:
        print('Subject(学科) %r' %(item))
    return templates.TemplateResponse("index.html", {"request": request})

@app.get("/output", tags=["Test Interfaces"])
def output(request: Request):
    GradeList = []
    for item in GradeName:
        grade = item.value
        # print('Grade(年级) %r' %(grade))
        GradeList.append(grade)
    DepartmentList = []
    for item in DepartmentName:
        department = item.value
        # print('Department(院系) %r' %(department))
        DepartmentList.append(department)
    MajorList = []
    for item in MajorName:
        major = item.value
        # print('Major(专业) %r' %(major))
        MajorList.append(major)
    
    return templates.TemplateResponse("output.html", {  "request": request,
                                                        "GradeList": GradeList,
                                                        "DepartmentList": DepartmentList,
                                                        "MajorList": MajorList
                                                        })

@app.post("/out", tags=["Test Interfaces"])
def out(request: Request, 
        grade: str = Form(...), 
        department: str = Form(...), 
        major: str = Form(...)):
    
    xlsxname = department+grade+major+'.xlsx'
    output = os.path.join(APP_OUTPUT, xlsxname)
    # print('Output Path : %r' %(output))

    # print('/out grade : %r' %(grade))
    # print('/out department : %r' %(department))
    # print('/out major : %r' %(major))
    wb=Workbook()
    # ws=wb.active
    wb.create_sheet(department+grade+major,0)
    ws=wb.active

    datas = None
    
    db = client.xinxi
    mStudent = db.student
    
    mResult = mStudent.find( {  "grade": grade,
                                "department": department,
                                "major": major }, {"_id" : 0} )
    dic = {"code": 404, "datas": {}}
    mResultList = []
    if mResult.count() == 0:
        print("Not Found !~")
    else:
        # print("Yeah Founds %r!~" %(mResult.count()))
        mResultList = list(mResult[:])

    mHeaderList = ['学号', '姓名' ]
    mMajorSet = []
    for item in mResultList:
        # print('no %r name %r grade %r 院系 %r 专业 %r.' %(   item["no"],
        #                                     item["name"],
        #                                     item["grade"],
        #                                     item["department"],
        #                                     item["major"]))
        if item["scores"]:
            print('dic len %r' %( len(item["scores"]) ))
            for item in item["scores"]:
                print(' %r.' %( item["course"]))
                mMajorSet.append(item["course"])
        break
    # print("mHeaderList %r mMajorSet %r" %(mHeaderList, mMajorSet))
    for item in mMajorSet:
        # print(item,end='')
        mHeaderList.append(item)
    ws.append(mHeaderList)

    for item in mResultList:
        # print('no %r name %r grade %r 院系 %r 专业 %r.' %(
        #                                     item["no"],
        #                                     item["name"],
        #                                     item["grade"],
        #                                     item["department"],
        #                                     item["major"]) )
        tmp=[item["no"],item["name"]]
        # print( 'mMajorSet : %r' %(mMajorSet) )
        # print( 'item : %r ...' %(item) )
        
        scores = item["scores"]
        # print( 'scores : %r' %(scores) )
        # for score in scores:
        #     print('score %r . type %r' %(score, type(score) ) )
            
        # print('x' * 30)

        for index, major in enumerate(mMajorSet):
            # print('index : %r' %(index) )
            # print('major %r index %r' %(major, index) )
            # print( 'item["scores"] : %r' %(item["scores"][index]) )

            t = 0

            for score in scores:
                # print('score : %r major: %r ssssss' %(score, major) )
                if major in score.values():
                    t = score['score']
                    break
                else:
                    t = -1
            # print('cur t : %r' %(t ) )
            # tmp.append(round(float(item["scores"][index]["score"])) )
            tmp.append(round(float( t )) )
            # print('tmp %r' %(tmp))
        
        ws.append(tmp)
    wb.save(output)

    return templates.TemplateResponse("out.html", { "request": request,
                                                    "xlsxname": xlsxname,
                                                    "datas": mResultList,
                                                    "output": output,
                                                    "department": department,
                                                    "major": major,
                                                    "grade" : grade})
